﻿using System.Collections;
using System.Windows;
using System.Windows.Media;
using System.Windows.Shapes;
using CommomFunctions;

namespace Filas
{
    public class ControlVariables : Controls
    {
        /// <summary>
        /// cont -> number of elements in the queue
        /// contElem -> counter for the automatic labeling. Keeps the index of the element that will be inserted to the queue
        /// contRemoved -> number of elements that had been removed from the queue
        /// position -> the position of the element that will be inserted
        /// myQueue -> a system queue that contains the elements of our queue 
        /// </summary>
        private static int cont = 0;
        private static int contElem = 0;
        private static int contRemoved = 0;        
        private static int position = 0;
        private static Queue myQueue = new Queue();
              

        public static int contAdd
        {
            get { return cont; }
            set { cont = value; }
        }

        /// <summary>
        /// Sets all labels and elements visibility to hidden
        /// </summary>
        internal static void setAllHidden()
        {
            elemLabels.setAllHidden();
            queueElements.setAllHidden();          
        }

        /// <summary>
        /// Resets the counters
        /// </summary>
        internal static void resetCounters()
        {
            contElem = 0;
            contAdd = 0;
            contRemoved = 0;
            position = 0;
        }

        /// <summary>
        /// Clears the queue content
        /// </summary>
        internal static void updateQueue()
        {
            myQueue.Clear();
        }

        /// <summary>
        /// Writes to trace the information about the operation being executed
        /// </summary>
        /// <param name="buttonClicked"></param>
        internal static void writeToTrace(ButtonClicked buttonClicked)
        {
            switch(buttonClicked)
            {
                case ButtonClicked.Create: txtTrace.writeTrace("\nCria nova fila vazia.\n", Brushes.RoyalBlue);            
                    break;
                case ButtonClicked.Destroy: txtTrace.writeTrace("\nDestrói a fila.\n", Brushes.RoyalBlue);
                    break;
                case ButtonClicked.Insert: txtTrace.writeTrace("Insere elemento " + contElem.ToString(), Brushes.Goldenrod);            
                    break;
                case ButtonClicked.Remove: txtTrace.writeTrace("Remove elemento " + myQueue.Dequeue().ToString(), Brushes.AntiqueWhite);
                    break;
            }
        }

        /// <summary>
        /// Tests if the queue is full
        /// </summary>
        /// <returns></returns>
        internal static bool testOverflow()
        {
            if (contAdd.Equals(queueElements.numElements))
            {
                txtTrace.writeTrace("Fila Cheia!\nOperação não pode ser realizada.", Brushes.Red);
                return true;
            }

            return false;
        }

        /// <summary>
        /// Tests if the queue is empty
        /// </summary>
        /// <returns></returns>
        internal static bool testUnderflow()
        {
            if ((contAdd < 1))
            {
                queueImages.setImagesVisibility(Visibility.Hidden);
                
                txtTrace.writeTrace("Fila vazia!\nOperação não pode ser realizada.", Brushes.Red);
                return true;
            }

            return false;
        }

        /// <summary>
        /// Inserts a new element in the queue.
        /// The insertion is done by updating the counters and setting the elements visibility.
        /// If all the elements had been removed the process re-start by reseting the "contRemoved" variable.
        /// </summary>
        internal static void insertElement()
        {
            if ((contAdd < 1))
                contRemoved = 0;

            if (contAdd != queueElements.numElements)
                contAdd++;

            contElem++;
            myQueue.Enqueue(contElem);

            queueElements.setVisibility(position, Visibility.Visible);
            elemLabels.setVisibility(contAdd - 1, Visibility.Visible);
            elemLabels.setContent(contAdd - 1, contElem.ToString());

            position++;
        }

        /// <summary>
        /// Animates the removal of an element.
        /// If the queue is empty only the Null image is visible. Otherwise, the images margin 
        /// and elements fill are updated. The buttons disponibility are updated too.
        /// The animation starts at index 1 instead of 0 because I always remove the first element.
        /// Each element is animated individually.
        /// </summary>
        internal static void animaRemove()
        {
            if ((contAdd < 1))
            {
                queueImages.setImagesVisibility(Visibility.Hidden);
                queueImages.setNullImagesVisibility(Visibility.Visible);               
            }
            else
            {
                queueImages.setMargin(WorkingImage.End, new Thickness((66 * (contAdd)), 20, (66 * (10 - contAdd + 1)), 32));

                for (int i = 1; i <= contAdd; i++)
                {
                    Animations.animaRemove(i);
                }

                queueElements.updateRectanglesFill(queueElements.numElements);

                ButtonClicked[] bc = {ButtonClicked.Insert, ButtonClicked.Remove};
                updateButtons(bc, false);
            }
        }

        /// <summary>
        /// Executed after the removal animation is completed, it updates the elements visibility, 
        /// the labels content and the buttons disponiblity.
        /// </summary>
        internal static void endAnimaRemove()
        {
            ArrayList tempLabels = new ArrayList();

            foreach (int mf in myQueue)
            {
                tempLabels.Add(mf);
            }
            for (int i = 0; i < contAdd; i++)//começa do 1 pq sempre removo o primeiro agora
            {
                queueElements.setVisibility(i, Visibility.Visible);
                elemLabels.setVisibility(i, Visibility.Visible);
                elemLabels.setContent(i, ((int)tempLabels[i]).ToString());
            }

            ButtonClicked[] bc = { ButtonClicked.Insert, ButtonClicked.Remove };
            updateButtons(bc, true);

        }

        /// <summary>
        /// Returns the rectangle at index "ind"
        /// </summary>
        /// <param name="ind"></param>
        /// <returns></returns>
        internal static Rectangle getRectangle(int ind)
        {
            return queueElements.getRectangle(ind);
        }

        /// <summary>
        /// Updates the disponibility of the buttons indicated by "inds" accordingly to "isEnabled"
        /// </summary>
        /// <param name="inds"></param>
        /// <param name="isEnabled"></param>
        private static void updateButtons(ButtonClicked[] inds, bool isEnabled)
        {
            Buttons.updateButtons(btns, inds, isEnabled);
        }

        /// <summary>
        /// Updates the counters when an element is removed
        /// </summary>
        internal static void updateCounters()
        {
            if (contRemoved.Equals(queueElements.numElements))
                contRemoved = 0;
            else contRemoved++;

            contAdd--;
            position--;
        }

        /// <summary>
        /// Updates the margin of the arrow pointing to the end of the queue whenever an element is inserted or removed 
        /// </summary>
        internal static void updateImageMargin()
        {
            queueImages.setMargin(WorkingImage.End, new Thickness((66 * (contAdd)), 20, (66 * (10 - contAdd + 1)), 32));
        }

        /// <summary>
        /// Updates the images visibility when an element is inserted.
        /// If the "Null" image was visible it means the queue was empty and the images 
        /// that indicate this emptyness must be set to hidden and the other images
        /// (indicating the begin and the end of the line) must be set to visible
        /// </summary>
        internal static void updateImagesVisibility()
        {
            if (queueImages.getVisibility(WorkingImage.Null) == Visibility.Visible)
                queueImages.setNullImagesVisibility(Visibility.Hidden);                
            
            queueImages.setImagesVisibility(Visibility.Visible);
        }

        /// <summary>
        /// Sets the properties of the "Null Images" (images that represent the emptyness of the queue)
        /// when a queue is created
        /// </summary>
        internal static void initializeNullImages()
        {
            queueImages.setNullImagesMargins(new Thickness(elemLabels.getLabel(0).Margin.Left, 15, elemLabels.getLabel(0).Margin.Right, 60),
            new Thickness(elemLabels.getLabel(0).Margin.Left, 90, elemLabels.getLabel(0).Margin.Right, 45),
            new Thickness(elemLabels.getLabel(contAdd).Margin.Left + 10, elemLabels.getLabel(contAdd).Margin.Top,
                          elemLabels.getLabel(contAdd).Margin.Right + 10, elemLabels.getLabel(contAdd).Margin.Bottom));

            queueImages.setHeight(WorkingImage.Null, 26);

            queueImages.setNullImagesVisibility(Visibility.Visible);            
        }

        

    }
}
